package com.heima.comment.service.impl;

import com.heima.comment.dto.ApUser;
import com.heima.comment.dto.CommentRepayDto;
import com.heima.comment.dto.CommentRepayLikeDto;
import com.heima.comment.dto.CommentRepaySaveDto;
import com.heima.comment.entity.ApComment;
import com.heima.comment.entity.ApCommentRepay;
import com.heima.comment.entity.ApCommentRepayLike;
import com.heima.comment.feign.UserFeign;
import com.heima.comment.service.ICommentRepayService;
import com.heima.comment.vo.ApCommentRepayVo;
import com.heima.common.dto.ResponseResult;
import com.heima.common.dto.User;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.util.AppThreadLocalUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class CommentRepayServiceImpl implements ICommentRepayService {

    @Autowired
    private UserFeign userFeign; // 用户feign远程调用

    @Autowired
    private MongoTemplate mongoTemplate; // mongo数据库

    /**
     * 发表回复
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveRepay(CommentRepaySaveDto dto) {
        //1.判断用户是否登录, 登录才可以发表评论
        User user = AppThreadLocalUtil.get();
        if (user != null) {
            //2. 登录后进行业务需求校验
            //2.1 判断内容是否大于140字  , 大于的话, 返回参数错误
            if (dto == null || StringUtils.isEmpty(dto.getContent()) || dto.getContent().length() > 140) {
                //返回参数错误信息
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
            }
            //3. 安全过滤, 集成阿里云进行审核 todo 待完成

            //4. 构建发表回复的对象, 保存回复记录
            ApCommentRepay repay = new ApCommentRepay();
            //4.1 加入用户id 从登录信息请求头里拿
            repay.setAuthorId(user.getUserId());
            //4.2 用户名称和用户头像
            // 2种方式获取
            // 第一种方式,在用户登录时将用户的名称和头像写入到token中,在网关解析,在拦截器中获取
            // 第二种方式,根据用户id到用户微服务进行查询, feign远程调用用户微服务
            ResponseResult<ApUser> responseResult = userFeign.getUserById(user.getUserId());
            //4.3 判断一下远程调用是否成功, 成功才返回数据,远程调用返回的状态码 与成功的状态码作对比
            if (responseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
                // 拿到远程调用的数据
                ApUser apUser = responseResult.getData();
                //001 加入作者的用户名
                repay.setAuthorName(apUser.getName());
            }
            //002 写入评论id, 从前端传入
            repay.setCommentId(dto.getCommentId());
            //005 写入评论内容, 从前端传入
            repay.setContent(dto.getContent());
            //006 写入点赞数, 开始为0
            repay.setLikes(0);
            //009 写入创建时间
            repay.setCreatedTime(new Date());
            //5. 保存评论 到mongoDB数据库
            mongoTemplate.save(repay);
            // 查询条件  评论id
            Query query = new Query();
            query.addCriteria(Criteria.where("id").is(dto.getCommentId()));
            // 更新条件 指定递增的字段和数量 回复数
            Update update = new Update();
            update.inc("reply");
            //6. mongo数据库,更新评论回复数量 +1
            mongoTemplate.updateFirst(query, update, ApComment.class);
            // 返回成功标识
            return ResponseResult.okResult();
        }
        //last 未登录返回未登录的提示信息
        return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
    }

    /**
     * 点赞回复, 给回复的点赞
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentRepayLikeDto dto) {
        //1.判断用户是否登录, 登录才可以发表评论
        User user = AppThreadLocalUtil.get();
        if (user != null) {
            //2. 根据回复id来进行点赞
            //2.1 构建点赞对象
            ApCommentRepayLike commentLike = new ApCommentRepayLike();
            //2.2 写入回复的id, 从前端传入
            commentLike.setCommentRepayId(dto.getCommentRepayId());
            //2.3 写入点赞, 0点赞, 1取消点赞, 从前端传入
            commentLike.setOperation(dto.getOperation());
            //2.4 写入用户ID
            commentLike.setAuthorId(user.getUserId());
            //3. 操作分为点赞和取消点赞
            // 如果是点赞,需要将点赞记录保存到 点赞记录表中
            // 判断当前用户针对当前评论是否已经有点赞记录, 根据用户ID和回复id 用mongo数据库进行条件查询
            Query query = new Query();
            query.addCriteria(Criteria.where("authorId").is(user.getUserId()));
            query.addCriteria(Criteria.where("commentRepayId").is(dto.getCommentRepayId()));
            ApCommentRepayLike one = mongoTemplate.findOne(query, ApCommentRepayLike.class);
            //4. 定义修改的增量
            int count = 0;
            //5. one == 0 说明没查到点赞记录
            if (one == null){
                // 咩点赞记录, 进行新增
                mongoTemplate.save(commentLike);
                // 增量加1
                count = 1;
            } else {
                // 如果数据库的状态和当前操作状态一致,不用处理
                // 不一致的话,修改状态,重新保存
                if (dto.getOperation() != one.getOperation()){
                    one.setOperation(dto.getOperation());
                    mongoTemplate.save(one);
                    if (dto.getOperation() == 0){
                        count = 1;
                    } else {
                        count = -1;
                    }
                }
            }
            //6. 需要将回复中的点赞量做修改
            if (count != 0){
                Query queryComment = new Query();
                //根据回复id 进行修改
                queryComment.addCriteria(Criteria.where("id").is(dto.getCommentRepayId()));
                Update update = new Update();
                // 指定递增的字段和数量, 点赞数
                update.inc("likes",count);
                //mongo进行 评论中点赞量进行修改修改
                mongoTemplate.updateFirst(queryComment, update, ApCommentRepay.class);
            }
            //7. 点赞完成, 返回前端成功标志
            return ResponseResult.okResult();
        }
        //last 未登录返回未登录的提示信息
        return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
    }

    /**
     * 加载回复列表, 恢复列表分页展示
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(CommentRepayDto dto) {
        //1. 根据评论id查询回复列表
        Query query = new Query();
        //2.评论id, 跟前端传入的评论id对比
        query.addCriteria(Criteria.where("commentId").is(dto.getCommentId()));
        //3. 根据前端传的最小时间查询, 和mongo的创建时间作对比
        query.addCriteria(Criteria.where("createdTime").lt(dto.getMinDate()));
        //4. 分页查询 指定当前页(从0开始)  每页条数  排序方向  排序字段
        Pageable page = PageRequest.of(0, 10, Sort.Direction.DESC, "createdTime");
        //5. 分页条件放进去
        query.with(page);
        // mongo条件查询
        List<ApCommentRepay> apComments = mongoTemplate.find(query, ApCommentRepay.class);

        //6. 构建给前端返回一个VO对象的集合 ApCommentRepayVo   0：点赞  1：取消点赞
        List<ApCommentRepayVo> vos = new ArrayList<>();
        // 遍历mongo查询的数据
        for (ApCommentRepay apComment : apComments) {
            // 构建ApCommentRepayVo对象
            ApCommentRepayVo vo = new ApCommentRepayVo();
            //遍历的数据copy 给vo
            BeanUtils.copyProperties(apComment, vo);
            //如果没有点赞, 存入vo对象
            vo.setOperation(1);
            //加入vo集合
            vos.add(vo);
        }
        //7. 判断用户是否是已经登录
        User user = AppThreadLocalUtil.get();
        // 如果没登录直接返回成功标志, 不做处理
        if (user == null){
            // 返回成功标志
            return ResponseResult.okResult();
        }
        //8. 如果登录,需要判断当前登录用户在查询到的回复列表中是否已经有点赞记录,如果有点赞记录,需要进行高亮显示
        Query likeQuery = new Query();
        // 根据用户ID 查询
        likeQuery.addCriteria(Criteria.where("authorId").is(user.getUserId()));
        // 提取所有评论的id 创建评论id的集合
        List<String> ids = new ArrayList<>();
        // 遍历 取到评价的id
        for (ApCommentRepay apComment : apComments) {
            // 将评论id 放入 评论id集合
            ids.add(apComment.getId());
        }
        // 将 评论id 集合放入查询条件中进行查询
        likeQuery.addCriteria(Criteria.where("commentRepayId").in(ids));
        //mongo条件查询
        List<ApCommentRepayLike> apCommentLikes = mongoTemplate.find(likeQuery, ApCommentRepayLike.class);
        //9. 定义所有点赞id集合
        List<String> listIds = new ArrayList<>();
        // 遍历所有的查询结果
        for (ApCommentRepayLike apCommentLike : apCommentLikes) {
            // 如果是0点赞了 把评论id加入到点赞集合
            if (apCommentLike.getOperation() == 0){
                listIds.add(apCommentLike.getCommentRepayId());
            }
        }
        //10. 遍历最后结果
        for (ApCommentRepayVo vo : vos) {
            if (listIds.contains(vo.getId())){
                vo.setOperation(0);
            }
        }
        //返回数据给前端
        return ResponseResult.okResult(vos);
    }
}
